﻿namespace S7.Net
{
    using System;
    using System.IO;
    using System.Net.Sockets;

    internal class COTP
    {
        public class TPDU
        {
            public byte[] Data;
            public byte HeaderLength;
            public bool LastDataUnit;
            public byte PDUType;
            public int TPDUNumber;

            public TPDU(TPKT tPKT)
            {
                BinaryReader reader = new BinaryReader(new MemoryStream(tPKT.Data));
                this.HeaderLength = reader.ReadByte();
                if (this.HeaderLength >= 2)
                {
                    this.PDUType = reader.ReadByte();
                    if (this.PDUType == 240)
                    {
                        byte num = reader.ReadByte();
                        this.TPDUNumber = num & 0x7f;
                        this.LastDataUnit = (num & 0x80) > 0;
                        this.Data = reader.ReadBytes((tPKT.Length - this.HeaderLength) - 4);
                        return;
                    }
                }
                this.Data = new byte[0];
            }

            public static COTP.TPDU Read(Socket socket)
            {
                TPKT tPKT = TPKT.Read(socket);
                if (tPKT.Length > 0)
                {
                    return new COTP.TPDU(tPKT);
                }
                return null;
            }

            public override string ToString()
            {
                object[] args = new object[] { this.HeaderLength, this.PDUType, this.TPDUNumber, this.LastDataUnit, BitConverter.ToString(this.Data) };
                return string.Format("Length: {0} PDUType: {1} TPDUNumber: {2} Last: {3} Segment Data: {4}", args);
            }
        }

        public class TSDU
        {
            public static byte[] Read(Socket socket)
            {
                COTP.TPDU tpdu = COTP.TPDU.Read(socket);
                if (tpdu == null)
                {
                    return null;
                }
                MemoryStream stream = new MemoryStream(tpdu.Data.Length);
                stream.Write(tpdu.Data, 0, tpdu.Data.Length);
                while (!tpdu.LastDataUnit)
                {
                    tpdu = COTP.TPDU.Read(socket);
                    stream.Write(tpdu.Data, (int) stream.Position, tpdu.Data.Length);
                }
                return stream.GetBuffer();
            }
        }
    }
}

